/**
 ************************************************************************************************************
 * template Class for managing multiple type of vectors.
 * Best fitted to 2-3-4D vectors, because of accessors, but can be applied to any dimensions
 * Specific operations like cross product are made in namespace RBMath
 ************************************************************************************************************
 * @file Vector.h
 ************************************************************************************************************/

#pragma once

#ifdef  HEADER_MSG
#pragma HEADER_MSG(Vector.h)
#endif

namespace RB
{
namespace Math
{


/************************************************************************************************************
 * Includes
 ************************************************************************************************************/
#include "Foundation/Platform/Types.h"
#include <RBMain/RBAssert.h>
#include <RBMain/RBMath.h>

/************************************************************************************************************
 * Forward declarations
 ************************************************************************************************************/
template<typename Type, uint32 Count> class RBVectorData          { public: Type Data[Count];};
template<typename Type, uint32 Count> class RBColorData           { public: Type Data[Count];};
#pragma warning(push)
#pragma warning(disable: 4201)
template<typename Type>               class RBVectorData<Type, 1> { public: union { struct { Type x;                         }; Type Data[1]; }; };
template<typename Type>               class RBVectorData<Type, 2> { public: union { struct { Type x; Type y;                 }; Type Data[2]; }; };
template<typename Type>               class RBVectorData<Type, 3> { public: union { struct { Type x; Type y; Type z;         }; Type Data[3];}; };
template<typename Type>               class RBVectorData<Type, 4> { public: union { struct { Type x; Type y; Type z; Type w; }; Type Data[4]; }; };

template<typename Type>               class RBColorData <Type, 1> { public: union { struct { Type r;                         }; Type Data[1]; }; };
template<typename Type>               class RBColorData <Type, 2> { public: union { struct { Type r; Type g;                 }; Type Data[2]; }; };
template<typename Type>               class RBColorData <Type, 3> { public: union { struct { Type r; Type g; Type b;         }; Type Data[3];}; };
template<typename Type>               class RBColorData <Type, 4> { public: union { struct { Type r; Type g; Type b; Type a; }; Type Data[4]; }; };

#pragma warning(pop)


/************************************************************************************************************
 * Class
 ************************************************************************************************************/
template<typename Type, uint32 Count, 
         template<typename T, uint32 C> class RBVectorBaseType = RBVectorData
        >
class RBVector : public RBVectorBaseType<Type, Count>
{
    typedef RBVector<Type, Count, RBVectorBaseType> ThisType;
public:
                    RBVector		();
                    RBVector		(Type scalar);
                    RBVector		(const ThisType& rhs);
                    RBVector        (Type x, Type y);
                    RBVector        (Type x, Type y, Type z);
                    RBVector        (Type x, Type y, Type z, Type w);
                   ~RBVector		();

    static const ThisType& Zero           ();

    Type&           operator()      (int i);
    Type            operator()      (int i) const;

    float32         Distance        (const ThisType& point) const;
    Type            SqrDistance     (const ThisType& point) const;

    float32         GetLength       () const;
    Type            GetSqrLength    () const;
	
    Type            Dot             (const ThisType& rhs) const;
    ThisType        Cross           (const ThisType& rhs) const;
    ThisType        Normalize       () const;

    ThisType        operator-		() const;
    ThisType		operator+		(const ThisType& rhs) const;
    ThisType		operator-		(const ThisType& rhs) const;
    ThisType		operator*		(Type scalar) const;
    ThisType		operator*		(const ThisType& rhs) const;
    ThisType&       operator=       (const ThisType& rhs);
    ThisType&       operator=       (Type scalar);
    ThisType&       operator+=      (const ThisType& rhs);
    ThisType&       operator-=      (const ThisType& rhs);
    ThisType&       operator*=      (const ThisType& rhs);
    ThisType&       operator*=      (Type scalar);
    ThisType&       operator/=      (Type scalar);


    template<typename Type, uint32 Count, template<typename T, uint32 C> class RBVectorBaseType>
    friend RBVector<Type, Count, RBVectorBaseType> operator*(Type scalar, 
															 const RBVector<Type, Count, RBVectorBaseType>& point);

    template<uint32 NewCount> 
    RBVector<Type, NewCount, RBVectorBaseType> To () const
    {
        RBCompileAssert(NewCount < Count);
        RBVector<Type, NewCount, RBVectorBaseType> ret;
        for (uint32 ui=0; ui < NewCount; ++ui)
        {
            ret(ui) = Data[ui];
        }
        return ret;
    }

};

/***********************************************************************************************************
 *
 ***********************************************************************************************************/

#include "RBVector.inl"

typedef RBVector<float32, 2, RBVectorData> float2;
typedef RBVector<float32, 3, RBVectorData> float3;
typedef RBVector<float32, 3, RBColorData>  RBColor;
typedef RBVector<float32, 4, RBColorData>  RBColorA;
typedef RBVector<uint8,   2, RBVectorData>  byte2;
typedef RBVector<uint8,   4, RBColorData>  byte4;
typedef RBVector<int32, 2,   RBVectorData> int2;
typedef RBVector<int32, 3,   RBVectorData> int3;
typedef RBVector<int32, 4,   RBVectorData> int4;


/************************************************************************************************************/

#endif // __RBVECTOR__H__
